Day 22
一堆樸克牌攤在眼前,要照花色排還是大小來排?隨你高興。
sort()
是個很好用的陣列方法,凡是要把陣列裡面的元素,照我們想排列的方式重新排列都需要用到它。例如在購物網站的商品依價格排列,或是我們看文章時,依照最近的時間排列,都會用到sort()
。
在做排序時,我們也會同時原地(in place)的更動到原陣列,且回傳給我們排好序的陣列。
Array.prototype.sort() - JavaScript | MDN
原型: Array.prototype.sort()
功能: 依據字串的 Unicode 編碼進行排序。
改變: 會改變原本的陣列
語法: arr.sort([compareFunction])
回傳值: 回傳排序後的陣列
參數: 可指定一個函式來定義排序的順序。如果省略此參數就會依據字串的 Unicode 編碼進行排序。
是依據什麼來排列?
sort()
是如何依照我們想要的方式排序?如果我們不給sort()
參數,它會依照預設的方式排序。我們也可以給一個函式當參數,並將條件寫在函式裡,這樣會比沒有給參數精準很多。
預設排序大亂入
預設排序也就是依照我們陣列裡元素的 code UTF-16 的順序排列,什麼是 code UTF-16? UTF-16 是 Unicode 字元的一種,我們可以直接看看這張 Unicode 的編碼表,並且來做一些測試:
1 | const arr1 = [ |
排序的結果頗讓人驚訝 簡直像沒排序,sort()
會將所有元素轉成字串後,且以第一個字元為對象,再進行排序,而所有符號會被先篩選出來,接著是數字,然後是字母。也因為這樣的比較,所以連200
都會排在8
前面。而字母則以字母大寫為先、小寫為後來排序。
需要特別注意的是,這樣的結果有可能因sort()
執行環境 也就是瀏覽器的不同,而有預期之外的預設排序結果。所以一般會建議,還是以函式傳入參數來當排序條件會比較穩定。
用匿名函式當排序條件
如果希望完全依照自己給的條件排序,最好是給sort()
一個帶有條件的匿名函式來當參數,這個匿名函數必須要有兩個參數,然後再依照這兩個參數比較回傳的值,來當排序依據。
sort()
會依匿名函式的參數與回傳的值為精確的排序規則:
- 當回傳值為負數時,那麼前面的數放在前面
- 當回傳值為正整數,那麼後面的數在前面
- 當回傳值為零,保持不動。
這個函式會每次都先拿兩組陣列裡的元素來比較,當回傳值為正,會讓後面的數跑到前面,以上述的規則來移動元素,大家有沒覺得這種方式很眼熟,其實就是使用冒泡排序法來達到排序。
我們先來看這些例子:
1 | // 沒有給參數的預設排序 |
或許大家會覺得疑惑,怎麼回傳一個 a - b
就變升序 b - a
就成了降序?
這是被精簡化的寫法 聽說高手都會越寫越精簡 ,我們可以來看看原本的寫法:
1 | const arr = [5, 9, 1, 3, 2, 6]; |
這就是程式好玩的地方,一步步的精簡到回傳a - b
就是升、b - a
就是降,還真是新手想不出來的境界啊!
可以拿 sort 來做什麼?
sort()
可以運用的範圍很廣,尤其是參數的匿名函式,依照下的條件不同而達到我們想要的效果。來看看一些範例:
按照字串長度來排序
1 | const arr = ['hi', 'Hello', 'Bonjour', 'ciao']; |
對字串做不區分大小寫的排序
我們在最開頭的時候有聊到,sort()
的預設會以 Unicode 來排序,而在 Unicode 的排序裡,大寫字母又會比小寫前面,但當我們要對有大小寫混雜的字串陣列做排序時,如何做到不區分大小寫的排序?可參考下列的方式,先把字串全轉成小寫再比對,就可以得到不分大小寫的排序囉。
1 | arr = ['apple', 'Banana', 'coco', 'Ege']; |
今天就先介紹到這裡,其實sort()
的學問很大,這其中牽涉到的不只是演算法,還有 JavaScript 裡的匿名函式的活用,本人才疏且學淺,好多知識都還來不及吸收,以致不敢介紹給大家,期待有朝一日的自己,可以回頭講解得更清楚些。
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~